﻿using Consul;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using SH.Common.CommonReturn;
using SH.Multitenant.Application.IServices.IApplicationForm;
using SH.Multitenant.Core.Saas;
using SH.Multitenant.Domain.WorkFlow;
using SH.Multitenant.Infrastructure.IRepository;
using SH.Multitenant.Infrastructure.Repository;
using SqlSugar;
using SqlSugar.Extensions;
using System.Collections.Generic;
using System.Security.Cryptography.Xml;
using Yitter.IdGenerator;

namespace SH.Multitenant.API.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class WorkFlowController : ControllerBase
    {

        private readonly ISqlSugarClient _context;

        public WorkFlowController()
        {
            _context = DbManger.BizDb;
        }

        /// <summary>
        /// 单线流程
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> GetWorkFlowObject(WorkFlowDTO dto, string flowName)
        {
            var tran = _context.AsTenant().UseTran();
            try
            {
                ApiResult<int> apiResult = new ApiResult<int>();
                List<FlowNode> nodes = new List<FlowNode>();

                #region 存储json到数据库
                //存储json到数据库
                string flowJson = JsonConvert.SerializeObject(dto);
                string flowId = YitIdHelper.NextId().ToString();
                var result = await _context.Insertable<CompletedWorkFlow>(new CompletedWorkFlow
                {
                    Id = flowId,
                    JsonString = flowJson,
                    FlowName = flowName,
                }).ExecuteCommandAsync();
                if (result == 0)
                {
                    apiResult.Error(ApiResult<int>.ErrorType.Service, "该工作流程添加失败");
                    tran.RollbackTran();
                    return Ok(apiResult);
                }
                #endregion

                #region 流程节点添加
                string startId = "";
                //寻找开始节点
                foreach (var item in dto.nodes)
                {
                    if (item.text.value == "开始")
                    {
                        startId = item.id;
                        var secondNodeId = dto.edges.Where(x => x.sourceNodeId == startId).SingleOrDefault().targetNodeId;
                        nodes.Add(new FlowNode
                        {
                            Id = YitIdHelper.NextId().ToString(),
                            NodeId = startId,
                            NodeName = "开始",
                            NextNodeId = secondNodeId,
                            CreateTime = DateTime.Now,
                            FlowId = flowId,
                        });
                        break;
                    }
                }
                //寻找下一级节点

                string nextId = "";
                foreach (var item in dto.edges)
                {
                    if (item.sourceNodeId == startId)
                    {
                        //获取节点id
                        nextId = item.targetNodeId;
                        //添加节点到流程节点表
                        FlowNode node = new FlowNode();
                        node.Id = YitIdHelper.NextId().ToString();
                        node.NodeId = nextId;
                        var currentNode = dto.nodes.Where(x => x.id == nextId).SingleOrDefault();
                        //判断当前流程块是否为空
                        if (currentNode == null)
                        {
                            apiResult.Error(ApiResult<int>.ErrorType.Service, "未找到对应的流程块");
                            tran.RollbackTran();
                            return Ok(apiResult);
                        }
                        node.NodeName = currentNode.text.value;
                        node.OperatorId = currentNode.properties.RoleId;
                        node.OperatorName = currentNode.properties.RoleName;
                        node.ProNodeId = startId;
                        //找下一节点id
                        var nextNode = dto.edges.Where(x => x.sourceNodeId == nextId).SingleOrDefault();
                        if (nextNode == null)
                        {
                            //node.NextNodeId = "";
                            //没有下一级节点即流程结束                        
                            node.CreateTime = DateTime.Now;
                            node.FlowId = flowId;
                            //添加结束节点
                            nodes.Add(node);
                            break;
                        }
                        node.NextNodeId = nextNode.targetNodeId;
                        node.CreateTime = DateTime.Now;
                        node.FlowId = flowId;
                        //添加节点
                        nodes.Add(node);
                        startId = nextId;
                    }
                }
                result = await _context.Insertable<FlowNode>(nodes).ExecuteCommandAsync();
                if (result == 0)
                {
                    apiResult.Error(ApiResult<int>.ErrorType.Service, "流程节点添加失败");
                    tran.RollbackTran();
                    return Ok(apiResult);
                }
                #endregion



                tran.CommitTran();
                apiResult.Success();
                return Ok(apiResult);
            }
            catch (Exception)
            {
                tran.RollbackTran();
                throw;
            }
        }

        /// <summary>
        /// 获取流程类型
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetFlowTypes()
        {
            var result = await _context.Queryable<CompletedWorkFlow>().Select(x => new
            {
                x.Id,
                x.FlowName
            }).ToListAsync();
            ApiResult<object> apiResult = new ApiResult<object>();
            apiResult.Success(result);
            return Ok(apiResult);
        }
        /// <summary>
        /// 新建流程单
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> CreateApplicationForm(ApplicationFormDTO dto)
        {
            ApiResult<int> apiResult = new ApiResult<int>();
            using var tran = _context.AsTenant().UseTran();
            try
            {
                //流程单添加
                var dateNow = DateTime.Now;
                var result = await _context.Insertable<ApplicationForm>(new ApplicationForm
                {
                    ApplicantId = dto.ApplicantId,
                    Applicant = dto.Applicant,
                    StartTime = dto.StartTime,
                    EndTime = dto.EndTime,
                    Reason = dto.Reason,
                    CreateTime = dateNow
                }).ExecuteReturnIdentityAsync();
                #region 创建流程实例并添加
                //找到流程类型对应的流程节点
                var nodeList = _context.Queryable<FlowNode>().Where(x => x.FlowId == dto.TypeId).ToList();
                //开始节点
                var startNode = nodeList.First(x => x.NodeName == "开始");
                //下个节点
                var nextNode = nodeList.First(x => x.ProNodeId == startNode.NodeId);
                //默认开始节点
                FlowInstance flowInstance = new FlowInstance()
                {
                    FlowInstanceId = DateTime.Now.Ticks.ToString(),
                    NodeId = startNode.NodeId,
                    NodeName = "开始",
                    FlowStatus = "已发起",
                    FlowInitiatorId = dto.ApplicantId,
                    FlowInitiatorName = dto.Applicant,
                    CurrentOperatorId = dto.ApplicantId,
                    CurrentOperatorName = dto.Applicant,
                    //待办人
                    NextOperatorId = nextNode.OperatorId,
                    NextOperatorName = nextNode.OperatorName,
                    HasOperatedPersons = dto.Applicant,
                    CreateTime = dateNow,
                    UpdTime = dateNow,
                    RequestId = result,
                };
                var returnResult = await _context.Insertable<FlowInstance>(flowInstance).ExecuteCommandAsync();
                #endregion
                //添加流程记录
                //判断流程实例是否添加成功
                if (returnResult == 0)
                {
                    tran.RollbackTran();
                    apiResult.Error(ApiResult<int>.ErrorType.Service, "流程实例添加失败");
                    return Ok(apiResult);
                }
                returnResult = await _context.Insertable<FlowRecord>(new FlowRecord
                {
                    Id = DateTime.Now.Ticks.ToString(),
                    FlowInstanceId = flowInstance.FlowInstanceId,
                    CurrentNodeId = startNode.NodeId,
                    CurrentNodeName = startNode.NodeName,
                    //操作人
                    OperatorId = flowInstance.CurrentOperatorId,
                    OperatorName = flowInstance.CurrentOperatorName,
                    CreateTime = DateTime.Now,
                    IsRead = true,
                    IsPassed = true,
                }).ExecuteCommandAsync();
                if (returnResult == 0)
                {
                    tran.RollbackTran();
                    apiResult.Error(ApiResult<int>.ErrorType.Service, "流程日志添加失败");
                    return Ok(apiResult);
                }
                //申请成功
                tran.CommitTran();
                apiResult.Success();
                return Ok(apiResult);
            }
            catch (Exception)
            {
                tran.RollbackTran();
                throw;
            }
        }

        /// <summary>
        /// 分页获取待办列表
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetTodoList(int roleId, int pageSize, int pageIndex)
        {
            var flowInstanceList = _context.Queryable<FlowInstance>().LeftJoin<ApplicationForm>((a, b) => a.RequestId == b.Id).Where((a, b) => a.NextOperatorId == roleId.ToString()).OrderByDescending((a, b) => a.UpdTime).Select((a, b) => new TodoItem
            {
                InstanceId = a.FlowInstanceId,
                Applicant = b.Applicant,
                PreOperator = a.CurrentOperatorName,
                UpdTime = a.UpdTime,
                Id = a.RequestId,
                StartTime = b.StartTime,
                EndTime = b.EndTime,
                Reason = b.Reason,
            });
            RefAsync<int> totalCount = 0;
            RefAsync<int> pageCount = 0;
            var pageList = await flowInstanceList.ToPageListAsync(pageIndex, pageSize, totalCount, pageCount);
            ApiPaging<List<TodoItem>> apiPaging = new ApiPaging<List<TodoItem>>() { Data = pageList, PageCount = pageCount, TotalCount = totalCount };
            return Ok(apiPaging);
        }

        /// <summary>
        /// 流程审批
        /// </summary>
        /// <param name="requestId"></param>
        /// <param name="passed"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> FlowExamination(int requestId, bool passed)
        {
            ApiResult<int> apiResult = new ApiResult<int>();
            using var tran = _context.AsTenant().UseTran();
            try
            {
                //添加操作日志
                var flowInstance = await _context.Queryable<FlowInstance>().FirstAsync(x => x.RequestId == requestId);
                //找到下个节点
                var nextNode = _context.Queryable<FlowNode>().First(x => x.ProNodeId == flowInstance.NodeId);
                var flowRecord = new FlowRecord()
                {
                    Id = DateTime.Now.Ticks.ToString(),
                    FlowInstanceId = flowInstance.FlowInstanceId,
                    CurrentNodeId = nextNode.NodeId,
                    CurrentNodeName = nextNode.NodeName,
                    OperatorId = flowInstance.NextOperatorId,
                    OperatorName = flowInstance.NextOperatorName,
                    CreateTime = DateTime.Now,
                    IsRead = true,
                    IsPassed = passed,
                };
                var result = await _context.Insertable<FlowRecord>(flowRecord).ExecuteCommandAsync();
                //判断是否添加成功
                if (result == 0)
                {
                    tran.RollbackTran();
                    apiResult.Error(ApiResult<int>.ErrorType.Service, "操作日志添加失败");
                    return Ok(apiResult);
                }
                //日志添加成功则修改流程实例
                flowInstance.FlowStatus = passed ? "已通过" : "已驳回";
                flowInstance.CurrentOperatorId = flowInstance.NextOperatorId;
                flowInstance.CurrentOperatorName = flowInstance.NextOperatorName;
                //根据已操作的节点找下一级节点
                var nextUnoperationNode = _context.Queryable<FlowNode>().First(x => x.ProNodeId == nextNode.NodeId);
                //判断下一级节点是否是结束
                //if (nextUnoperationNode.NodeName.Contains("结束"))
                //{
                //    
                //}
                if (passed)
                {
                    flowInstance.NodeId = nextNode.NodeId;
                    flowInstance.NodeName = nextNode.NodeName;
                    flowInstance.NextOperatorId = nextUnoperationNode.OperatorId;
                    flowInstance.NextOperatorName = nextUnoperationNode.OperatorName;
                    flowInstance.HasOperatedPersons += "," + flowRecord.OperatorName;
                    flowInstance.UpdTime = DateTime.Now;
                    result = await _context.Updateable<FlowInstance>(flowInstance).ExecuteCommandAsync();
                }
                else
                {
                    flowInstance.NextOperatorId = null;
                    flowInstance.NextOperatorName = null;
                    flowInstance.HasOperatedPersons += "," + flowRecord.OperatorName;
                    flowInstance.UpdTime = DateTime.Now;
                    result = await _context.Updateable<FlowInstance>(flowInstance).ExecuteCommandAsync();
                }
                //判断是否修改成功
                if (result == 0)
                {
                    tran.RollbackTran();
                    apiResult.Error(ApiResult<int>.ErrorType.Service, "修改流程实例失败");
                    return Ok(apiResult);
                }
                //修改成功
                tran.CommitTran();
                apiResult.Success();
                return Ok(apiResult);
            }
            catch (Exception)
            {
                tran.RollbackTran();
                throw;
            }
        }

        /// <summary>
        /// 已发起的流程
        /// </summary>
        /// <param name="empId"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetAppliedFlows(string empId)
        {
            var list = await _context.Queryable<FlowInstance>().LeftJoin<ApplicationForm>((a, b) => a.RequestId == b.Id)
                .Where(a => a.FlowInitiatorId == empId).ToListAsync();
            ApiResult<object> apiResult = new ApiResult<object>();
            apiResult.Success(list);
            return Ok(apiResult);
        }

        #region 流程节点
        public class WorkFlowDTO
        {
            public Node[] nodes { get; set; }
            public Edge[] edges { get; set; }
        }

        public class Node
        {
            public string id { get; set; }
            public string type { get; set; }
            public int x { get; set; }
            public int y { get; set; }
            public Properties properties { get; set; }
            public Text text { get; set; }
        }

        public class Properties
        {
            public string? start { get; set; }
            public string? CustomRect { get; set; }
            public string? RoleId { get; set; }
            public string? RoleName { get; set; }
        }

        public class Text
        {
            public int x { get; set; }
            public int y { get; set; }
            public string value { get; set; }
        }

        public class Edge
        {
            public string id { get; set; }
            public string type { get; set; }
            public string sourceNodeId { get; set; }
            public string targetNodeId { get; set; }
            public Startpoint startPoint { get; set; }
            public Endpoint endPoint { get; set; }
            public Properties properties { get; set; }
            public Pointslist[] pointsList { get; set; }
        }

        public class Startpoint
        {
            public int x { get; set; }
            public int y { get; set; }
        }

        public class Endpoint
        {
            public int x { get; set; }
            public int y { get; set; }
        }



        public class Pointslist
        {
            public int x { get; set; }
            public int y { get; set; }
        }
        #endregion

    }
}
